// ┏┓　　　┏┓
// ┏┛┻━━━┛┻┓
// ┃　　　　　　　┃ 　
// ┃　　　━　　　┃
// ┃　┳┛　┗┳　┃
// ┃　　　　　　　┃
// ┃　　　┻　　　┃
// ┃　　　　　　　┃
// ┗━┓　　　┏━┛
// ┃　　　┃ 神兽保佑　　　　　　　　
// ┃　　　┃ 代码无BUG！
// ┃　　　┗━━━┓
// ┃　　　　　　　┣┓
// ┃　　　　　　　┏┛
// ┗┓┓┏━┳┓┏┛
// ┃┫┫　┃┫┫
// ┗┻┛　┗┻┛
using NetDimension.NanUI.ChromiumCore;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Printing;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;
using TicketTaking.Tool;

namespace TicketTaking
{
    public class JSBridgeObject : JSObject
    {
        private Main _mainForm;
        private volatile bool _inScanPage = false;
        private volatile bool _inScanPageIC = false;
        private volatile bool _inScanPagePay = false;
        

        public JSBridgeObject(Main mainForm)
        {
            this._mainForm = mainForm;

            AddFunction("mounted").Execute += PageMounted;
 
            AddFunction("printByCode").Execute += PrintByCode;
            AddFunction("startScan").Execute += StartScan;
            AddFunction("stopScan").Execute += StopScan;
            AddFunction("startScanIC").Execute += startScanIC;
            AddFunction("exit").Execute += ((o, e) => {_mainForm.Vbar.Backlight(false);Application.Exit();});

            AddFunction("showDevTools").Execute += (s, e) => _mainForm.ShowDevTools();
        }

        private void PageMounted(object sender, Chromium.Remote.Event.CfrV8HandlerExecuteEventArgs e)
        {
            try
            {
                // need do nothing
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
            }
        }

        public void KeepScan()
        {
            while (true)
            {
                if (_inScanPage)
                {
                    try
                    {
                        byte[] result;
                        if (_mainForm.Vbar.Scan(out result))
                        {
                            string auth_code = System.Text.Encoding.Default.GetString(result);
                            auth_code = Regex.Replace(auth_code, @"[^\d]*", ""); 
                            
                            LogHelper.Debug($"扫码成功：{auth_code}");
                            // _mainForm.Invoke(new Action(() =>{System.Windows.Forms.MessageBox.Show("扫码成功：" + code);}));
                            _mainForm.Vbar.Beep(1);
                            _mainForm.Vbar.Backlight(false);   
                            _inScanPage = false;
                            _mainForm.ExecuteJavascript($"vm.page='paywait';vm.auth_code='{auth_code}';$$.unblockUI();");                 
                            // 跳转到成功页面

                            // var tuple = Pay(code); 

                            // // 跳转到选择张数页                        
                            // // 跳转到成功页面
                            // LogHelper.Debug($"结束扫码..."); 
                            // _inScanPageIC = false; 
                            // if (tuple.Item1 != 1)
                            // {
                            //     LogHelper.Debug($"code后台查询失败：{tuple.Item1}—{tuple.Item2}"); 
                            //     _inScanPage = false;
                            //     _mainForm.ExecuteJavascript($"vm.page='paywait';vm.order_id='{order_id}';$$.unblockUI();");
                            // }else{
                            //     LogHelper.Debug($"code后台查询：{tuple.Item1}—{tuple.Item2}"); 
                            //     _inScanPage = false;
                            //     _mainForm.ExecuteJavascript($"vm.page='paywait';vm.order_id='{order_id}';$$.unblockUI();");
                            // }

                            

                        }
                        else
                        {
                            //LogHelper.Debug($".");
                        }
                    }
                    catch (Exception ex)
                    {
                        LogHelper.Error(ex);
                        LogHelper.Debug($"结束扫码...");
                        _mainForm.Vbar.Backlight(false);
                        _inScanPage = false;
                        _mainForm.ExecuteJavascript("vm.page='err';");
                    }
                }
            }
        }
        public void KeepScanIC()
        {
            while (true)
            {
                if (_inScanPageIC)
                {
                    try
                    {
                        byte[] result;
                        if (_mainForm.ICReader.ReadCard(out result))
                        {
                            string code_16 = System.Text.Encoding.Default.GetString(result);
                            
                            int num = Convert.ToInt32(code_16, 16);
                            string code = Convert.ToString(num);
                            LogHelper.Debug($"手环识别成功16：{code_16}");
                            //if (code.Length > 16) code = code.Substring(0, 16);

                            LogHelper.Debug($"手环识别成功：{code}");
                            // _mainForm.Invoke(new Action(() =>{System.Windows.Forms.MessageBox.Show( code+ "扫码成功：" + code_16);}));
                            _mainForm.ICReader.Beep(2);  
                            _mainForm.ExecuteJavascript($"$$.blockUI();"); 
                            // 验证code
                            var tuple = QueryCode(code); 

                            // 跳转到选择张数页                        
                            // 跳转到成功页面
                            LogHelper.Debug($"结束手环识别...");
                            _inScanPageIC = false; 
                            if (tuple.Item1 != 1)
                            {
                                LogHelper.Debug($"code后台查询失败：{tuple.Item1}—{tuple.Item2}");
                                LogHelper.Debug($"结束手环识别...");
                                _inScanPageIC = false;
                                _mainForm.ExecuteJavascript($"vm.page='order';vm.hasVip=false;$$.unblockUI();"); 
                            }else{ 
                                LogHelper.Debug($"code后台查询：{tuple.Item1}—{tuple.Item2}—{tuple.Item3}—{tuple.Item4}—{tuple.Item5}—{tuple.Item6}—{tuple.Item7}");

                                LogHelper.Debug($"结束手环识别1...");
                                _inScanPageIC = false;
                                int hasVip = tuple.Item2 == 'o'.ToString() ? 1 : 0;
                                _mainForm.ExecuteJavascript($"vm.page='order';vm.hasVip={hasVip};vm.code='{code}';vm.order_status='{tuple.Item3}';vm.order_time='{tuple.Item4}';vm.product_id={tuple.Item5};vm.product_price_id={tuple.Item6};vm.product_price={tuple.Item7};$$.unblockUI();");

                            }
                        }
                        else
                        {
                            //LogHelper.Debug($".");
                        }
                    }
                    catch (Exception ex)
                    {
                        LogHelper.Error(ex);
                        LogHelper.Debug($"结束手环识别err..."); 
                        _inScanPageIC = false;
                        _mainForm.ExecuteJavascript("vm.page='err';");
                    }
                }
            }
        }

        public void KeepQuery(string order_id)
        {
            while (true)
            {
                if (_inScanPagePay)
                {
                    try
                    {
                        var tuple = QueryPay(order_id);
                        if (tuple.Item1==1 && tuple.Item4==1)
                        {
                            //支付成功
                            _inScanPagePay = false;   
                            LogHelper.Debug($"查询支付结果成功...成功"); 
                            PrintTicket(tuple.Item2); 
                            _mainForm.ExecuteJavascript("vm.page='suc';vm.code='';$$.unblockUI();");
                        }
                        else if(tuple.Item1==1 && tuple.Item4==3){
                            //支付取消
                            _inScanPagePay = false;  
                            LogHelper.Debug($"查询支付结果成功...取消"); 
                            _mainForm.ExecuteJavascript("vm.page='err';vm.code='';$$.unblockUI();");
                        }
                        else
                        {
                            continue;
                            //LogHelper.Debug($".");
                        }
                    }
                    catch (Exception ex)
                    {
                        LogHelper.Error(ex);
                        LogHelper.Debug($"支付err..."); 
                        _inScanPagePay = false; 
                    }
                }
            }
        }

        private void PrintByCode(object sender, Chromium.Remote.Event.CfrV8HandlerExecuteEventArgs e)
        {
            try
            {
                if(e.Arguments.Length != 7) return; 
                int pay = e.Arguments[0].IntValue;
                string product = e.Arguments[1].StringValue;
                int product_id = e.Arguments[2].IntValue;
                double price = e.Arguments[3].DoubleValue;
                string auth_code = e.Arguments[4].StringValue;
                int product_price_id = e.Arguments[5].IntValue;
                string code = e.Arguments[6].StringValue;
                
                Task.Factory.StartNew(() =>
                {
                    try
                    {
                        // 验证code
                        // var tuple = VerifyCode(code,quantity);
                        //付款
                        //(int pay,string product,int price,string auth_code,int product_id,int product_price_id, string code)
                        
                        var tuple = Pay(pay, product, price, auth_code, product_id, product_price_id, code);
                        LogHelper.Debug($"支付参数：{pay}—{product}—{price}—{auth_code}—{product_id}—{product_price_id}—{code}");
                        // 请求错误
                        if (tuple.Item1 != 1)
                        {
                            LogHelper.Debug($"支付失败：{tuple.Item1}—{tuple.Item2}");
                            _mainForm.ExecuteJavascript($"vm.page='err';$$.unblockUI();$$.error('{tuple.Item2}');");
                            return;
                        }else{
                            if(pay==1){   
                                LogHelper.Debug($"支付宝成功：打印：{tuple.Item5}");
                                PrintTicket(tuple.Item5); 
                                _mainForm.ExecuteJavascript("vm.page='suc';vm.code='';$$.unblockUI();");
                            }else{
                                if(tuple.Item4==1){
                                    string print_content = "";
                                    LogHelper.Debug($"微信成功：打印：{tuple.Item5}");
                                    PrintTicket(tuple.Item5); 
                                    _mainForm.ExecuteJavascript("vm.page='suc';vm.code='';$$.unblockUI();");
                                }else if(tuple.Item4==4){
                                    //等待输入密码
                                    _inScanPagePay = true;
                                    KeepQuery(tuple.Item3);

                                }
                            }
                        }

                        
                    }
                    catch (Exception ex)
                    {
                        LogHelper.Debug($"支付失败：打印失败");
                        _mainForm.ExecuteJavascript("vm.page='err';$$.unblockUI();");
                        LogHelper.Error(ex);
                    }
                });
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
            }
        }



        private void StartScan(object sender, Chromium.Remote.Event.CfrV8HandlerExecuteEventArgs e)
        {
            try
            {
                LogHelper.Debug($"开始扫码...");
                _mainForm.Vbar.Backlight(true);
                _inScanPage = true;
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
            }
        }

        private void startScanIC(object sender, Chromium.Remote.Event.CfrV8HandlerExecuteEventArgs e)
        {
            try
            {
                LogHelper.Debug($"开始识别手环...");
                _inScanPageIC = true;
                 
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
            }
        }

        private void StopScanIC(object sender, Chromium.Remote.Event.CfrV8HandlerExecuteEventArgs e)
        {
            try
            {
                LogHelper.Debug($"结束扫码...");
                //_mainForm.ICReader.Backlight(false);
                _inScanPageIC = false;
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
            }
        }
        private void StopScan(object sender, Chromium.Remote.Event.CfrV8HandlerExecuteEventArgs e)
        {
            try
            {
                LogHelper.Debug($"结束扫码...");
                _mainForm.Vbar.Backlight(false);
                _inScanPage = false;
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
            }
        }

        private Tuple<int, string, string,int,int> QueryPay(string order_id)
        {
            string client = _mainForm.Settings.Client;
            string str = Newtonsoft.Json.JsonConvert.SerializeObject(new
            {
                username = _mainForm.Settings.Username,
                password = _mainForm.Settings.Password,
                id = order_id,
                method = "status",
            });
            string data = StrUtil.AesEncrypt(str, _mainForm.Settings.Secret);
            
            UTF8Encoding encoding = new UTF8Encoding();

            //client = StrUtil.UrlEncode(client);
            //data = StrUtil.UrlEncode(data);

            //string postData = $"client={client}&data={data}";
            string postData = Newtonsoft.Json.JsonConvert.SerializeObject(new
            {
                client = client,
                data = data,
            });
            byte[] postByte = encoding.GetBytes(postData);
            LogHelper.Debug($"开始查询支付状态：{postData}");

            HttpWebRequest myRequest = (HttpWebRequest)HttpWebRequest.Create(_mainForm.Settings.RequestUrl);
            myRequest.Method = "POST";
            //request.ContentType = "application/x-www-form-urlencoded";
            myRequest.ContentType = "application/json; charset=utf-8";
            myRequest.ContentLength = postByte.Length;
            Stream newStream = myRequest.GetRequestStream();
            newStream.Write(postByte, 0, postByte.Length);
            newStream.Close();

            HttpWebResponse myResponse = (HttpWebResponse)myRequest.GetResponse();
            StreamReader reader = new StreamReader(myResponse.GetResponseStream(), Encoding.UTF8);
            string content = reader.ReadToEnd();
            LogHelper.Debug($"支付返回{content}");

            var jObject = JObject.Parse(content);

            int returnCode = (int)jObject["code"];
            string returnMsg = jObject["message"].ToString();
            string id = jObject["order_id"]?.ToString();
            int status = (int)jObject["status"];
            int status_code = (int)jObject["status_code"];
            return new Tuple<int, string,string,int,int>(returnCode, returnMsg,id,status,status_code); 
        }

        /**
          status,msg,orderid,productName,可用数量
         */
        private Tuple<int, string, string,string,int,int,string> QueryCode(string code)
        {
           
           string client = _mainForm.Settings.Client;
            string str = Newtonsoft.Json.JsonConvert.SerializeObject(new
            {
                username = _mainForm.Settings.Username,
                password = _mainForm.Settings.Password,
                code = code,
                method = "querybracelet",
            });
            string data = StrUtil.AesEncrypt(str, _mainForm.Settings.Secret);
            
            UTF8Encoding encoding = new UTF8Encoding();

            //client = StrUtil.UrlEncode(client);
            //data = StrUtil.UrlEncode(data);

            //string postData = $"client={client}&data={data}";
            string postData = Newtonsoft.Json.JsonConvert.SerializeObject(new
            {
                client = client,
                data = data,
            });
            byte[] postByte = encoding.GetBytes(postData);
            LogHelper.Debug($"开始查询：{postData}");

            HttpWebRequest myRequest = (HttpWebRequest)HttpWebRequest.Create(_mainForm.Settings.RequestUrl);
            myRequest.Method = "POST";
            //request.ContentType = "application/x-www-form-urlencoded";
            myRequest.ContentType = "application/json; charset=utf-8";
            myRequest.ContentLength = postByte.Length;
            Stream newStream = myRequest.GetRequestStream();
            newStream.Write(postByte, 0, postByte.Length);
            newStream.Close();

            HttpWebResponse myResponse = (HttpWebResponse)myRequest.GetResponse();
            StreamReader reader = new StreamReader(myResponse.GetResponseStream(), Encoding.UTF8);
            string content = reader.ReadToEnd();
            LogHelper.Debug($"结束查询：{content}");

            var jObject = JObject.Parse(content);

            int returnCode = (int)jObject["code"];
            bool hasVip = (bool)jObject["order"];
            string returnMsg = hasVip? 'o'.ToString(): jObject["message"].ToString();
            string order_status = hasVip ? jObject["order_status"]?.ToString():null;
            string order_time = hasVip ? jObject["order_time"]?.ToString() : null;
            int product_id = returnCode == 1 ? (int)jObject["product_id"] : 0;
            int product_price_id = returnCode == 1 ? (int)jObject["product_product_id"] : 0;
            string product_price = returnCode == 1 ? jObject["product_price"]?.ToString() :null;

            return new Tuple<int, string, string,string,int,int,string>(returnCode, returnMsg, order_status,order_time,product_id,product_price_id,product_price);
        }

        /// <summary>
        /// 支付
        /// </summary>
        /// <param name="pay">1支付宝2微信</param>
        /// <param name="product">描述</param>
        /// <param name="price">价格</param>
        /// <param name="auth_code">付款码</param>
        /// <param name="product_id">产品id</param>
        /// <param name="product_price_id">套餐id</param>
        /// <param name="code">手环</param>
        /// <returns></returns>
        private Tuple<int, string,string,int,string> Pay(int pay,string product,double price,string auth_code,int product_id,int product_price_id, string code)
        {
            string client = _mainForm.Settings.Client;
            string str = Newtonsoft.Json.JsonConvert.SerializeObject(new
            {
                username = _mainForm.Settings.Username,
                password = _mainForm.Settings.Password,
                pay = pay,
                product = product,
                total_price = Math.Round( price,2),
                auth_code = auth_code,
                product_id = product_id,
                product_price_id = product_price_id,
                bracelet_code = code,
                method = "pay",
            });
            string data = StrUtil.AesEncrypt(str, _mainForm.Settings.Secret);

            UTF8Encoding encoding = new UTF8Encoding();

            //client = StrUtil.UrlEncode(client);
            //data = StrUtil.UrlEncode(data);

            //string postData = $"client={client}&data={data}";
            string postData = Newtonsoft.Json.JsonConvert.SerializeObject(new
            {
                client = client,
                data = data,
            });
            byte[] postByte = encoding.GetBytes(postData);
            LogHelper.Debug($"开始支付：{postData}");

            HttpWebRequest myRequest = (HttpWebRequest)HttpWebRequest.Create(_mainForm.Settings.RequestUrl);
            myRequest.Method = "POST";
            //request.ContentType = "application/x-www-form-urlencoded";
            myRequest.ContentType = "application/json; charset=utf-8";
            myRequest.ContentLength = postByte.Length;
            Stream newStream = myRequest.GetRequestStream();
            newStream.Write(postByte, 0, postByte.Length);
            newStream.Close();

            HttpWebResponse myResponse = (HttpWebResponse)myRequest.GetResponse();
            StreamReader reader = new StreamReader(myResponse.GetResponseStream(), Encoding.UTF8);
            string content = reader.ReadToEnd();
            LogHelper.Debug($"结束支付：{content}");

            var jObject = JObject.Parse(content);

            int returnCode = (int)jObject["code"];
            string returnMsg =  jObject["message"].ToString();
            int status = (int)jObject["status"];
            string order_id = jObject["order_id"].ToString();
            string printContent = jObject["printContent"]?.ToString();
            return new Tuple<int, string,string,int,string>(returnCode, returnMsg,order_id,status,printContent);
        }
        private StringReader lineReader;
        private string _ticketContent;
        private void PrintTicket(string ticketContent)
        {
            if (string.IsNullOrEmpty(ticketContent))
            {
                LogHelper.Debug("打印内容为空");
                return;
            }

            lineReader = new StringReader(ticketContent);
            _ticketContent = ticketContent;

            var doc = new PrintDocument();
            doc.PrintController = new StandardPrintController();
            doc.DefaultPageSettings.PaperSize = new PaperSize("Custum", 278, 273);
            doc.DefaultPageSettings.Margins = new Margins(0, 0, 0, 0);
            doc.PrintPage += Doc_PrintPage;
            doc.Print();
        }
        private void Doc_PrintPage(object sender, PrintPageEventArgs e)
        {
            var fontTitle = new Font(new FontFamily("黑体"), 16, FontStyle.Bold);
            var fontNormal = new Font(new FontFamily("黑体"), 14);

            Graphics g = e.Graphics;
            float linesPerPage = 0;
            float xPosition = 0;
            float yPosition = 0;
            int count = 0;
            float leftMargin = e.MarginBounds.Left;
            float topMargin = e.MarginBounds.Top;
            string line = null;
            SolidBrush myBrush = new SolidBrush(Color.Black);
            linesPerPage = e.MarginBounds.Height / fontNormal.GetHeight(g);

            while (count < linesPerPage && ((line = lineReader.ReadLine()) != null))
            {
                Font nowFont = count == 0 ? fontTitle : fontNormal;

                // title 居中
                if (count == 0)
                {
                    Size size = StrUtil.MeasureString(line, nowFont);
                    xPosition = leftMargin + (e.MarginBounds.Width - size.Width) / 2;
                    yPosition = topMargin + (count * nowFont.GetHeight(g));

                    g.DrawString(line, nowFont, myBrush, xPosition, yPosition, new StringFormat());
                    count++;
                }
                else
                {
                    // 内容可能超长
                    List<string> subLines = StrUtil.SplitStringByWidth(line, e.MarginBounds.Width, nowFont);
                    subLines.ForEach(subLine =>
                    {
                        xPosition = leftMargin;
                        yPosition = topMargin + (count * nowFont.GetHeight(g));

                        g.DrawString(subLine, nowFont, myBrush, xPosition, yPosition, new StringFormat());
                        count++;
                    });
                }

            }

            if (line != null)
                e.HasMorePages = true;
            else
            {
                e.HasMorePages = false;
                lineReader = new StringReader(_ticketContent);
            }
        }
    }
}
